package top.aicey.ai.sparring.biz.impl;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;

import top.aicey.ai.sparring.biz.ISceneBiz;
import top.aicey.ai.sparring.common.constants.EntityConstants;
import top.aicey.ai.sparring.common.constants.QueryParamsConstants;
import top.aicey.ai.sparring.dto.enums.SceneStatusEnum;
import top.aicey.ai.sparring.dto.req.SaveSceneRequestDto;
import top.aicey.ai.sparring.dto.req.SceneQaDto;
import top.aicey.ai.sparring.dto.res.AdminSceneResponse;
import top.aicey.ai.sparring.dto.res.SceneDetailResponse;
import top.aicey.ai.sparring.dto.res.SceneResponse;
import top.aicey.ai.sparring.entity.Scene;
import top.aicey.ai.sparring.entity.SceneQaPairs;
import top.aicey.ai.sparring.service.ISceneQaPairsService;
import top.aicey.ai.sparring.service.ISceneService;

/**
 * @author yangyongping
 * @date 2025-01-14 11:05 下午
 */
@Service
public class SceneBizImpl implements ISceneBiz {

    @Autowired
    private ISceneService sceneService;

    @Autowired
    private ISceneQaPairsService sceneQaPairsService;

    @Override
    public PageInfo<SceneResponse> pageQuery(String moduleId, Integer pageNumber, Integer pageSize) {
        Page<Scene> page = PageHelper.startPage(pageNumber, pageSize);
        page.doSelectPageInfo(() -> {
            sceneService.list(Wrappers.query(Scene.class).eq(EntityConstants.STATUS, SceneStatusEnum.RELEASE.getValue())
                .eq(EntityConstants.MODULE_ID, moduleId).orderByDesc(EntityConstants.CREATED_AT));
        });

        PageInfo<SceneResponse> pageInfo = page.toPageInfo(scene -> {
            SceneResponse response = new SceneResponse();
            response.setId(scene.getId());
            response.setName(scene.getName());
            response.setIcon(scene.getIcon());
            response.setSceneDescribe(scene.getSceneDescribe());
            response.setCreateTime(scene.getCreatedAt());
            return response;
        });
        return pageInfo;
    }

    @Override
    public PageInfo<AdminSceneResponse> pageAdminQuery(String moduleId, Integer pageNumber, Integer pageSize,
        Map<String, Object> params) {
        Page<Scene> page = PageHelper.startPage(pageNumber, pageSize);
        page.doSelectPageInfo(() -> {
            QueryWrapper<Scene> queryWrapper = Wrappers.query(Scene.class).eq(EntityConstants.MODULE_ID, moduleId);
            SceneStatusEnum status = (SceneStatusEnum)params.get(QueryParamsConstants.STATUS);
            if (Objects.nonNull(status)) {
                queryWrapper.eq(EntityConstants.STATUS, status.getValue());
            }
            queryWrapper.orderByDesc(EntityConstants.CREATED_AT);
            String keyword = (String)params.get(QueryParamsConstants.KEYWORD);
            queryWrapper.eq(StringUtils.isNotBlank(keyword), EntityConstants.NAME, keyword);
            sceneService.list(queryWrapper);
        });

        PageInfo<AdminSceneResponse> pageInfo = page.toPageInfo(scene -> {
            AdminSceneResponse response = new AdminSceneResponse();
            response.setId(scene.getId());
            response.setName(scene.getName());
            response.setIcon(scene.getIcon());
            response.setSceneDescribe(scene.getSceneDescribe());
            response.setCreateTime(scene.getCreatedAt());
            response.setNum(scene.getNum());
            response.setStatusEnum(SceneStatusEnum.getEnumByValue(scene.getStatus()));
            return response;
        });

        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void numAdd(Long sceneId) {
        sceneService.numAdd(sceneId);
    }

    /**
     * 检查场景是否存在
     *
     * @param id
     * @return
     */
    @Override
    public Boolean exists(Long id) {
        return sceneService.exists(Wrappers.query(Scene.class).eq(EntityConstants.ID, id));
    }

    /**
     * 通过id删除
     *
     * @param id
     */
    @Override
    public Boolean removeById(Long id) {
        return sceneService.removeById(id);
    }

    /**
     * 新增场景
     *
     * @param moduleId
     * @param userId
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long save(String moduleId, String userId, SaveSceneRequestDto dto) {
        Scene scene = buildScene(moduleId, userId, dto);
        // 保存基础场景信息
        sceneService.save(scene);
        // 保存问答对信息
        List<SceneQaDto> qaList = dto.getQaList();

        Long sceneId = scene.getId();

        List<SceneQaPairs> qaPairsList = Lists.newArrayList();
        for (SceneQaDto qaDto : qaList) {
            SceneQaPairs qaPairs = buildSceneQaPairs(qaDto, sceneId, moduleId, userId);
            qaPairsList.add(qaPairs);
        }

        // 记住其溯源
        sceneQaPairsService.saveBatch(qaPairsList);

        return scene.getId();
    }

    /**
     * 状态修改
     * @param sceneId
     * @param statusEnum
     * @param moduleId
     * @param userId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean statusChange(Long sceneId, SceneStatusEnum statusEnum, String moduleId, String userId) {
        Scene scene = new Scene();
        scene.setId(sceneId);
        scene.setModuleId(moduleId);
        scene.setStatus(statusEnum.getValue());
        scene.setUpdatedAt(LocalDateTime.now());
        scene.setUpdatedBy(userId);
        return sceneService.updateById(scene);
    }

    /**
     * 更新
     *
     * @param moduleId
     * @param userId
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(String moduleId, String userId, SaveSceneRequestDto dto) {

        Scene scene = buildScene(moduleId, userId, dto);

        // 保存问答对信息
        Long sceneId = dto.getId();
        List<SceneQaPairs> qaPairsList = Lists.newArrayList();
        for (SceneQaDto qaDto : dto.getQaList()) {
            SceneQaPairs qaPairs = buildSceneQaPairs(qaDto, sceneId, moduleId, userId);
            qaPairsList.add(qaPairs);
        }
        List<SceneQaPairs> dbQaPairs = sceneQaPairsService.listBySceneId(moduleId, sceneId);

        editDeleteQaPairs(dbQaPairs, qaPairsList);
        saveOrUpdateQaPairs(qaPairsList);
        return sceneService.updateById(scene);
    }

    @Override
    public SceneDetailResponse listDetailBySceneId(String moduleId, Long id) {

        Scene scene = sceneService.getById(id);

        if (Objects.isNull(scene)){
            return new SceneDetailResponse();
        }

        List<SceneQaPairs> qaPairs = sceneQaPairsService.listBySceneId(moduleId,id);

        SceneDetailResponse response = convertSceneDetailResponse(moduleId,scene, qaPairs);
        // 保存基础场景信息
        return response;
    }

    private void editDeleteQaPairs(List<SceneQaPairs> dbQaPairs, List<SceneQaPairs> qaPairsList) {
        // 数据库的ids
        List<Long> dbExistsIds = dbQaPairs.stream().map(SceneQaPairs::getId).collect(Collectors.toList());
        // 用户的ids
        List<Long> userExistsIds =
            qaPairsList.stream().map(SceneQaPairs::getId).filter(Objects::nonNull).collect(Collectors.toList());
        // 用户已经删除的ids
        List<Long> removeIds = Lists.newArrayList(dbExistsIds);

        removeIds.removeAll(userExistsIds);
        if (!CollectionUtils.isEmpty(removeIds)) {
            sceneQaPairsService.removeBatchByIds(removeIds);
        }
    }

    private void saveOrUpdateQaPairs(List<SceneQaPairs> qaPairsList) {
        sceneQaPairsService.saveOrUpdateBatch(qaPairsList);
    }

    private @NotNull Scene buildScene(String moduleId, String userId, SaveSceneRequestDto dto) {
        Scene scene = new Scene();
        scene.setStatus(SceneStatusEnum.DRAFT.getValue());
        scene.setModuleId(moduleId);
        scene.setCreatedBy(userId);
        scene.setCustomPrompt(dto.getCustomPrompt());
        scene.setName(dto.getName());
        scene.setSceneDescribe(dto.getSceneDescribe());
        scene.setIcon(dto.getIcon());
        scene.setDimensions(Joiner.on(",").skipNulls().join(dto.getDimensions()));
        return scene;
    }

    private @NotNull SceneQaPairs buildSceneQaPairs(SceneQaDto qaDto, Long sceneId, String moduleId, String userId) {
        SceneQaPairs qaPairs = new SceneQaPairs();
        qaPairs.setSceneId(sceneId);
        qaPairs.setModuleId(moduleId);
        qaPairs.setQuestion(qaDto.getQuestion());
        qaPairs.setAnswer(qaDto.getAnswer());
        qaPairs.setCreatedAt(LocalDateTime.now());
        qaPairs.setCreatedBy(userId);
        qaPairs.setUpdatedBy(userId);
        return qaPairs;
    }

    private @NotNull SceneDetailResponse convertSceneDetailResponse(String moduleId,Scene scene, List<SceneQaPairs> qaPairs) {
        SceneDetailResponse response = new SceneDetailResponse();
        response.setId(scene.getId());
        response.setName(scene.getName());
        response.setIcon(scene.getIcon());
        response.setSceneDescribe(scene.getSceneDescribe());
        response.setCustomPrompt(scene.getCustomPrompt());
        response.setDimensions(Splitter.on(",").trimResults().splitToList(scene.getDimensions()));
        response.setQaList(convertQaList(qaPairs));

        return response;
    }

    private List<SceneQaDto> convertQaList(List<SceneQaPairs> qaPairs) {
        List<SceneQaDto> list = Lists.newArrayList();
        for (SceneQaPairs qaPair : qaPairs) {
            SceneQaDto sceneQaDto = new SceneQaDto();
            sceneQaDto.setId(qaPair.getId());
            sceneQaDto.setQuestion(qaPair.getQuestion());
            sceneQaDto.setAnswer(qaPair.getAnswer());
            list.add(sceneQaDto);
        }
        return list;
    }

}
